package com.cn.backup.task;


import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.*;

/**
 * @Description : MYSQL数据库导出备份
 * @Author : Bruce Lee
 * @CreateTime : 2024/7/24
 */

@Slf4j
@Component
@Configuration
@EnableScheduling
public class DataBackUp {
    // 备份命令：mysqldump
    private String cmd = "mysqldump  -u{USERNAME} -p{PASSWORD} -h{SERVERPATH} -P{PORT} --databases {DBNAME} > {FILEPATH}";

    @Value("${spring.datasource.username}")
    private String userName;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.url}")
    private String serverPath;

    @Value("${backup.path}")
    private String prefix;


    /**
     * 判断文件是否存在，不存在创建
     */
    private static void existsFile(File file) {
        // 判断文件路径是否存在,不存在新建
        // file.getParentFile()用于获取当前文件或目录的父目录
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 核心思想：1.判断操作系统类型
     *         2.执行备份命令mysqldump
     *         3.判断文件存储路径是否存在，若不存在则创建
     *         4、通过文件流的形式将数据写入到文件中
     */
    @Scheduled(cron = "0/30 * * * * ?")
    public void backup() throws IOException {
        log.info("开始备份MySQL数据库");
        String subServerPath = serverPath.replace("jdbc:mysql://", "");
        // 数据库名
        String dbName = serverPath.substring(serverPath.lastIndexOf("/") + 1, serverPath.lastIndexOf("?"));
        // 文件名
        String pathFileName = prefix + dbName + ".sql";

        String[] split = subServerPath.split(":");
        // 服务器地址
        String serviceIP = split[0];
        // 服务器MySQL端口
        String port = split[1].substring(0, split[1].lastIndexOf("/"));


        String newCmd = cmd.replace("{USERNAME}", userName)
                .replace("{PASSWORD}", password)
                .replace("{SERVERPATH}", serviceIP)
                .replace("{PORT}", port)
                .replace("{DBNAME}", dbName)
                .replace("{FILEPATH}", pathFileName);

        log.info("备份数据库命令：{}", newCmd);

        Process process = null;
        PrintWriter printWriter = null;
        BufferedReader bufferedReader = null;
        InputStreamReader inputStreamReader = null;
        // 获取操作系统类型
        String property = System.getProperty("os.name");
        try {
            if (property.toLowerCase().contains("windows")) {
                // windows：执行备份命令
                try {
                    // 类似于在cmd中执行newCmd命令
                    process = Runtime.getRuntime().exec(newCmd);
                } catch (Exception e) {
                    log.error("备份数据库失败：{}", e.getMessage());
                }
            } else {
                // Linux: 执行备份命令
                try {
                    process = Runtime.getRuntime().exec(new String[]{"bash", "-c", newCmd});
                } catch (Exception e) {
                    log.error("备份数据库失败：{}", e.getMessage());
                }
            }

            inputStreamReader = new InputStreamReader(process.getInputStream(), "utf8");

            // 主要作用是快速读取字符数据，它可以从文件、输入流、网络连接等读取数据，并将其存储在缓冲区中
            bufferedReader = new BufferedReader(inputStreamReader);

            existsFile(new File(pathFileName));
            // 输出备份结果
            printWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(pathFileName), "utf8"));

            String line;
            while ((line = bufferedReader.readLine()) != null) {
                // 该函数使用printWriter对象将line字符串输出到指定的输出流中，并在输出后添加一个换行符
                printWriter.println(line);
            }
        } catch (Exception e) {
            log.error("备份数据库失败：{}", e.getMessage());

        } finally {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
            if (printWriter != null) {
                printWriter.close();
            }
            if (inputStreamReader != null){
                inputStreamReader.close();
            }
        }
        log.info("备份数据库成功");
    }
}
